package com.soms.servlet;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.json.JSONUtil;
import com.soms.constants.LoginConst;
import com.soms.service.UserService;
import com.soms.service.impl.UserServiceImpl;
import com.soms.util.HttpResponseUtil;
import com.soms.util.ResultUtil;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.Map;

/**
 * 获取验证码和登录校验，不登录就能够访问的资源
 */
@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    private final UserService userService = new UserServiceImpl();

    @Override
    protected void doGet(HttpServletRequest req,
                         HttpServletResponse resp)
            throws ServletException, IOException {
        String type = req.getParameter("type");
        if (type != null) {
            switch (type) {
                case "captcha":
                    getCaptcha(req, resp);
                    break;
                case "login":
                    doLogin(req, resp);
                    break;
                default:

                    break;
            }
        }
    }

    @Override
    protected void doPost(HttpServletRequest req,
                          HttpServletResponse resp)
            throws ServletException, IOException {
        doGet(req, resp);
    }

    /**
     * 获取验证码图片
     *
     * @param req
     * @param resp
     */
    private void getCaptcha(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 对象中会包含图片数据和验证码字符串
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(120, 40);
        HttpSession session = req.getSession();
        // 判断当前会话是否已经有用户登录了
        Object sessionUserCode = session.getAttribute(LoginConst.USER_CODE);
        if (sessionUserCode == null) {
            // 已经登录了，就不存储验证码，是因为系统应该防止用户反复登录
            // 不同的客户端要分别存储，会话技术（Session）
            session.setAttribute(LoginConst.CAPTCHA, lineCaptcha.getCode());
            // 设置会话有效期60秒：验证码保存60秒
            session.setMaxInactiveInterval(LoginConst.CAPTCHA_TIMEOUT);
        }
        ServletOutputStream os = resp.getOutputStream();
        lineCaptcha.write(os);
        os.flush();
        os.close();
    }

    /**
     * 登录校验
     *
     * @param req
     * @param resp
     */
    private void doLogin(HttpServletRequest req, HttpServletResponse resp) throws IOException {
        // 判断是否存在session，不存在也不新建，如果session中没有验证码，都算验证码失效
        HttpSession session = req.getSession(false);
        // 先判断是否已经登录了
        if (session != null && session.getAttribute(LoginConst.USER_CODE) != null) {
            HttpResponseUtil.writeJson(resp, JSONUtil.toJsonStr(ResultUtil.isAuthenticated()));
            return;
        }
        // 再判断是否有存验证码
        if(session == null || session.getAttribute(LoginConst.CAPTCHA) == null) {
            HttpResponseUtil.writeJson(resp, JSONUtil.toJsonStr(ResultUtil.fail("验证码已失效")));
            return;
        }
        // 获取session中的验证码字符串
        String code  = (String)session.getAttribute(LoginConst.CAPTCHA);
        // 获取前端请求参数中的验证码字符串
        String captcha = req.getParameter("captcha");
        // 核对验证码，忽略字母大小写
        if (!code.equalsIgnoreCase(captcha)) {
            HttpResponseUtil.writeJson(resp, JSONUtil.toJsonStr(ResultUtil.fail("验证码错误")));
            return;
        }
        // 登录校验
        String userCode = req.getParameter("userCode");
        String userPassword = req.getParameter("userPassword");
        Map<String, Object> result = userService.doLogin(userCode, userPassword);
        if (result.get("code").equals(200)) {
            // 能够登录成功，存储登录凭证到会话中
            // 登录凭证是需要包含用户关键信息的
            // 销毁原来存有验证码的会话
            session.invalidate();
            // 重新创建会话，从这一刻开始记录登录时间
            session = req.getSession(true);
            session.setAttribute(LoginConst.USER_CODE, userCode);
            session.setMaxInactiveInterval(LoginConst.USER_CODE_TIMEOUT);
        }
        HttpResponseUtil.writeJson(resp, JSONUtil.toJsonStr(result));
    }
}
